package binding

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"reflect"
)

type jsonBinding struct {
	DisallowUnknownFields bool
	IsValidate            bool
}

func (b *jsonBinding) Name() string {
	return "json"
}

func (b *jsonBinding) Bind(r *http.Request, obj any) error {
	body := r.Body
	// post 传参的内存 是放在body中
	if body == nil {
		return errors.New("invalid request")
	}
	decoder := json.NewDecoder(body)
	// 如果想要实现参数中有的属性，但是对应的结构体没有，报错，也就是检查结构体是否有效
	if b.DisallowUnknownFields {
		decoder.DisallowUnknownFields()
	}

	if b.IsValidate {
		err := validateParam(obj, decoder)
		if err != nil {
			return err
		}
	} else {
		return decoder.Decode(obj)
	}

	return validate(obj)
}

func validate(obj any) error {

	return Validator.ValidateStruct(obj)
}
func validateParam(obj any, decoder *json.Decoder) error {

	// 反射
	valueOf := reflect.ValueOf(obj)
	// 判断其是否为指针类型
	if valueOf.Kind() != reflect.Ptr {
		return errors.New("This argument must have a pointer type")
	}
	// 从指针 --- 解析为普通 value
	// 获取其元素类型.Interface()
	elem := valueOf.Elem().Interface()
	// 根据元素获取其值
	of := reflect.ValueOf(elem)

	switch of.Kind() {
	case reflect.Struct:
		return checkParam(of, obj, decoder)
	case reflect.Slice, reflect.Array:
		elem := of.Type().Elem()
		if elem.Kind() == reflect.Struct {
			return checkParamSlice(elem, obj, decoder)
		}

	default:
		_ = decoder.Decode(obj)
	}

	return nil

}

func checkParamSlice(elem reflect.Type, obj any, decode *json.Decoder) error {
	mapData := make([]map[string]interface{}, 0)

	_ = decode.Decode(&mapData)
	if len(mapData) == 0 {
		return nil
	}
	for i := 0; i < elem.NumField(); i++ {
		field := elem.Field(i)
		required := field.Tag.Get("msgo")
		tag := field.Tag.Get("json")

		for j := 0; j < len(mapData); j++ {
			value := mapData[j][tag]
			if value == nil && required == "required" {
				return errors.New(fmt.Sprintf(fmt.Sprintf("filed [%s] is required", tag)))
			}
		}
	}
	// 赋值
	if obj != nil {
		marshal, _ := json.Marshal(mapData)
		_ = json.Unmarshal(marshal, obj)
	}

	return nil
}

func checkParam(of reflect.Value, obj any, decoder *json.Decoder) error {
	// 思路：解析为map,然后根据map中的key, 进行比对
	// 判断类型 结构体 才能解析为map
	mapValue := make(map[string]interface{})
	_ = decoder.Decode(&mapValue) // 只能读取一次，读取一次后流读取完毕
	for i := 1; i < of.NumField(); i++ {
		field := of.Type().Field(i)
		name := field.Name
		jsonName := field.Tag.Get("json")
		if jsonName != "" {
			name = jsonName
		}

		required := field.Tag.Get("msgo")

		value := mapValue[name]
		if value == nil && required == "required" {
			return errors.New(fmt.Sprintf("filed [%s] is not exist, because [%s] is required", jsonName, jsonName))
		}
		fmt.Println("field name:", name)
	}
	marshal, _ := json.Marshal(mapValue)
	_ = json.Unmarshal(marshal, obj)

	return nil
}
